#include <iostream>
#include <deque>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include <cassert>
// zdl:: version -2
#include "./condClass/Cond.hpp"
#include "./condClass/Mutex.hpp"

using std::cout, std::endl, std::cin;
namespace  blockQueueModule
{
    using namespace mutexModule;
    using namespace condModule;
    static const int gcp = 10;
    template<class T>
    class blockQueue
    {
    private:
        std::queue<T> _q;
        uint _cap; // 定义主容器的最大容量
        Cond _consumer_cond;   // 消费者条件变量
        Cond _productor_cond; // 生产者条件变量
        Mutex _mutex; // 实现互斥
        int _c_wait_num;
        int _p_wait_num;
        bool isfull()
        {
            return _q.size() == _cap;
        }
        bool isempty()
        {
            return _q.size() == 0;
        }
    public:
        blockQueue(int cap = gcp) : _cap(cap), 
        _p_wait_num(0),
        _c_wait_num(0)
        {

        }
        ~blockQueue()
        {

        }
        void equeue(const T& data)
        {
            LockGuard lockguard(_mutex);
            while (isfull()) // ??
            {
                std::cout << "生产者进入等待" << std::endl;
                _p_wait_num++;
                _productor_cond.wait(_mutex);
                // 我们在临界区等待是必然的（目前）
                // zdl:: wait 时我们是必然持有锁
                _p_wait_num--;

                std::cout << "生产者被叫醒。。。" << std::endl;
            }
            _q.emplace(data); // 生产
            // zdl:: 做到这里就是一定有数据

            if (_c_wait_num)
            {
                cout << "叫醒生产者..." <<endl;
                _consumer_cond.notify();
            }
        }
        void pop(T* x)
        {
            while (isempty())
            {
                LockGuard lockguard(_mutex);
                std::cout << "消费者进入等待" << std::endl;
                ++_c_wait_num;
                _consumer_cond.wait(_mutex);
                // 我们在临界区等待是必然的（目前）
                // zdl:: wait 时我们是必然持有锁
                --_c_wait_num;
            }
            *x = _q.front(); _q.pop();

            // zdl:: 走到了这里就是还有空间存在，所以此时我就缓刑相应的没事情干的生产者，然他继续生产！
            if (_p_wait_num)
            {
                std::cout << "叫醒生产者..." << std::endl;
                _productor_cond.notify();
            }
            // return x;
        }
    };
    

    
}

    // zdl:: 现在我们需要寻找到一些方式来重塑自己的大脑

    // zdl:: version-1
    // template <class t>
    // class blockQueue
    // {
    // private:
    //     bool isFull()
    //     {
    //         return _qu.size() == _cap;
    //     }
    //     bool isEmpty() { return _qu.empty(); }

    // public:
    //     blockQueue(int cap = 10) : _cap(cap), _cwait_num(0), _pwait_num(0)
    //     {
    //         pthread_mutex_init(&_mutex, nullptr);
    //         pthread_cond_init(&_productor_cond, nullptr);
    //         pthread_cond_init(&_consumer_cond, nullptr);
    //     }
    //     ~blockQueue()
    //     {
    //         pthread_mutex_destroy(&_mutex);
    //         pthread_cond_destroy(&_consumer_cond);
    //         pthread_cond_destroy(&_productor_cond);
    //     }
    //     void Equeue(const t &in)
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         // zdl:: 到那时，你想放数据你就可以放数据么？
    //         // 结论一：再临界区等到是必然的（目前）
    //         // 等待的时候是一定持有锁的（这样有错！）
    //         while (isFull()) //?  对条件判断，为了我防止伪唤醒，我们通常使用while 进行条件判断
    //         {
    //             _pwait_num++;
    //             // 等时， 释放_mutex
    //             pthread_cond_wait(&_productor_cond, &_mutex); // wait 是必然的
    //             // 返回线程被唤醒, 重新申请锁（他会在临界区醒来
    //             _pwait_num--;
    //         }
    //         // 4. 线程被唤醒 || 条件不满足
    //         _qu.push(in);

    //         // 此时队列中一定有数据， 此时可以将消费者唤醒
    //         if (_cwait_num)
    //         {
    //             pthread_cond_signal(&_consumer_cond);
    //         }
    //         pthread_mutex_unlock(&_mutex);
    //     }
    //     void Pop(t *out)
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         while (isEmpty())
    //         {
    //             // ??
    //             _cwait_num++;
    //             pthread_cond_wait(&_consumer_cond, &_mutex);
    //             _cwait_num--;
    //         }
    //         // ifempty isn't been satisfied;

    //         *out = _qu.front();
    //         _qu.pop();

    //         // 走到这里就说明队列中一定有空间
    //         pthread_cond_signal(&_productor_cond);
    //         pthread_mutex_unlock(&_mutex);
    //     }

    // private:
    //     std::queue<t> _qu;      // 临界资源
    //     int _cap;               // 阻塞队列的最大容量
    //     pthread_mutex_t _mutex; // 互斥
    //     pthread_cond_t _productor_cond;
    //     pthread_cond_t _consumer_cond;
    //     int _cwait_num;
    //     int _pwait_num;
    // };

// }
// namespace zdl
// {
//     using namespace LockModule;
//     using namespace condMoudle;
//     static const int gcp = 10;
//     template<class T>
//     class blockQueue
//     {
//     private:
//         std::queue<T> _q;
//         uint _cap; // 定义主容器的最大容量
//         cond _consumer_cond;   // 消费者条件变量
//         cond _productor_cond; // 生产者条件变量
//         Mutex _mutex; // 实现互斥
//         int _c_wait_num;
//         int _p_wait_num;
//         bool isfull()
//         {
//             return _q.size() == _cap;
//         }
//         bool isempty()
//         {
//             return _q.size() == 0;
//         }
//     public:
//         blockQueue(int cap = gcp) : _cap(cap), 
//         _p_wait_num(0),
//         _c_wait_num(0)
//         {

//         }
//         ~blockQueue()
//         {

//         }
//         void equeue(const T& data)
//         {
//             LockGuard lockguard(_mutex);
//             while (isfull()) // ??
//             {
//                 std::cout << "生产者进入等待" << std::endl;
//                 _p_wait_num++;
//                 _productor_cond.wait(_mutex);
//                 // 我们在临界区等待是必然的（目前）
//                 // zdl:: wait 时我们是必然持有锁
//                 _p_wait_num--;

//                 std::cout << "生产者被叫醒。。。" << std::endl;
//             }
//             _q.emplace(data); // 生产
//             // zdl:: 做到这里就是一定有数据

//             if (_c_wait_num)
//             {
//                 cout << "叫醒生产者..." <<endl;
//                 _consumer_cond.modify();
//             }
//         }
//         T pop()
//         {
//             while (isempty())
//             {
//                 LockGuard lockguard(_mutex);
//                 std::cout << "消费者进入等待" << std::endl;
//                 ++_c_wait_num;
//                 _consumer_cond.wait(_mutex);
//                 // 我们在临界区等待是必然的（目前）
//                 // zdl:: wait 时我们是必然持有锁
//                 --_c_wait_num;
//             }
//             auto x = _q.front(); _q.pop();

//             // zdl:: 走到了这里就是还有空间存在，所以此时我就缓刑相应的没事情干的生产者，然他继续生产！
//             if (_p_wait_num)
//             {
//                 std::cout << "叫醒生产者..." << std::endl;
//                 _productor_cond.modify();
//             }
//             return x;
//         }
//     };
    

    
// }